import { LoginCanvasType } from './hook-types'

interface CanvasAttr {
  readonly [propname: string]: unknown
}

interface GradientColors {
  coordinate: number
  color: string
}

interface GradientOption {
  coordinate: number[]
  colors: GradientColors[]
}

interface PathPoint {
  x: number
  y: number
}

interface TextObj {
  startPoint: number[]
  text: string
  font: string
}

export class LoginCanvas implements LoginCanvasType {
  private dom: HTMLCanvasElement
  private ctx: CanvasRenderingContext2D
  private RECK_LINE_WIDTH: number
  private color: string[]
  private RECK_1: number[]
  private PATH_1: number[]
  private PATH_1_POINTS: PathPoint[]
  private PATH_2: number[]
  private PATH_2_POINTS: PathPoint[]
  private PATH_3: number[]
  private PATH_3_POINTS: PathPoint[]
  private PATH_4: number[]
  private PATH_4_POINTS: PathPoint[]
  private width: number
  private height: number
  private timer: NodeJS.Timer | null | undefined
  private TEXT1: TextObj
  private TEXT2: TextObj
  private TEXT3: TextObj
  private TEXT4: TextObj

  constructor(dom: HTMLCanvasElement | null) {
    this.dom = dom as HTMLCanvasElement
    this.width = this.dom.width
    this.height = this.dom.height
    this.RECK_LINE_WIDTH = 4
    this.color = ['#fff', '#FF9D00']
    const startPoint: number[] = [this.width / 2 - 400, this.height / 2 - 200]
    this.RECK_1 = [startPoint[0], startPoint[1], 140, 140]
    this.PATH_1 = [0, startPoint[1] + 100]
    this.PATH_1_POINTS = [
      {
        x: startPoint[0] - 2,
        y: startPoint[1] + 100
      }
    ]
    this.PATH_2 = [startPoint[0] + 140, startPoint[1] + 80]
    this.PATH_2_POINTS = [
      {
        x: this.PATH_2[0] + 120,
        y: this.PATH_2[1]
      },
      {
        x: this.PATH_2[0] + 120,
        y: this.PATH_2[1] + 140
      },
      {
        x: this.PATH_2[0] - 40,
        y: this.PATH_2[1] + 140
      },
      {
        x: this.PATH_2[0] - 40,
        y: this.PATH_2[1] + 60
      }
    ]
    this.PATH_3 = [startPoint[0] + 100, startPoint[1] + 200]
    this.PATH_3_POINTS = [
      {
        x: this.PATH_3[0] - 80,
        y: this.PATH_3[1]
      },
      {
        x: this.PATH_3[0] - 80,
        y: this.PATH_3[1] + 120
      },
      {
        x: this.PATH_3[0] + 80,
        y: this.PATH_3[1] + 120
      },
      {
        x: this.PATH_3[0] + 80,
        y: this.PATH_3[1] + 20
      }
    ]
    this.PATH_4 = [startPoint[0] + 260, startPoint[1] + 190]
    this.PATH_4_POINTS = [
      {
        x: this.PATH_4[0] + 600,
        y: this.PATH_4[1]
      },
      {
        x: this.PATH_4[0] + 600,
        y: this.height
      }
    ]
    this.TEXT1 = {
      startPoint: [startPoint[0] + 40, startPoint[1] + 90],
      text: '中',
      font: '60px SimSun, Songti SC'
    }
    this.TEXT2 = {
      startPoint: [startPoint[0] + 40, startPoint[1] + 280],
      text: '台',
      font: '60px SimSun, Songti SC'
    }
    this.TEXT3 = {
      startPoint: [startPoint[0] + 160, startPoint[1] + 20],
      text: '管',
      font: '60px SimSun, Songti SC'
    }
    this.TEXT4 = {
      startPoint: [startPoint[0] + 160, startPoint[1] + 170],
      text: '理',
      font: '60px SimSun, Songti SC'
    }
    this.ctx = this.dom.getContext('2d') as CanvasRenderingContext2D
    this.draw(0)
  }
  private draw(count: number) {
    const reckStyle = this.formatReckStyle([0, 0, this.width, this.height], this.color, count)
    const gradient = this.addLineGradient(reckStyle)
    this.drawPath(this.PATH_1, this.PATH_1_POINTS, { strokeStyle: gradient, lineWidth: this.RECK_LINE_WIDTH })
    this.drawStrokeReck(this.RECK_1, {})
    this.drawPath(this.PATH_2, this.PATH_2_POINTS, {})
    this.drawPath(this.PATH_3, this.PATH_3_POINTS, {})
    this.drawPath(this.PATH_4, this.PATH_4_POINTS, {})
    this.writeText(this.TEXT1, {})
    this.writeText(this.TEXT2, {})
    this.writeText(this.TEXT3, {})
    this.writeText(this.TEXT4, {})
  }
  private writeText(textObj: TextObj, attrs: CanvasAttr) {
    Object.assign(this.ctx, attrs)
    this.ctx.font = textObj.font
    this.ctx.lineWidth = 1
    this.ctx.strokeText(textObj.text, textObj.startPoint[0], textObj.startPoint[1])
  }
  private formatReckStyle(point: number[], colors: string[], count: number) {
    const style: GradientOption = {
      coordinate: point,
      colors: []
    }
    for (let i = 0; i < 100; i++) {
      if (i % 10 === count) {
        style.colors.push({
          coordinate: i / 100,
          color: Math.trunc(i / 10) % 2 === 1 ? colors[0] : colors[1]
        })
      }
    }

    return style
  }
  private addLineGradient(gradientOption: GradientOption) {
    const gradient = this.ctx.createLinearGradient(
      gradientOption.coordinate[0],
      gradientOption.coordinate[1],
      gradientOption.coordinate[2],
      gradientOption.coordinate[3]
    )

    gradientOption.colors.forEach(item => {
      gradient.addColorStop(item.coordinate, item.color)
    })

    return gradient
  }
  private drawPath(startPoints: number[], linePoints: PathPoint[], attrs: CanvasAttr) {
    this.ctx.beginPath()
    this.ctx.moveTo(startPoints[0], startPoints[1])
    linePoints.forEach(item => {
      this.ctx.lineTo(item.x, item.y)
    })
    Object.assign(this.ctx, attrs)
    this.ctx.stroke()
    this.ctx.closePath()
  }
  private drawStrokeReck(coordinate: number[], attrs: CanvasAttr) {
    Object.assign(this.ctx, attrs)
    this.ctx.strokeRect(coordinate[0], coordinate[1], coordinate[2], coordinate[3])
  }
  clear() {
    this.ctx.clearRect(0, 0, 2000, 1000)
  }
  startAnima() {
    let count = 0
    this.timer = setInterval(() => {
      if (count < 9) {
        count++
      } else {
        ;[this.color[0], this.color[1]] = [this.color[1], this.color[0]]
        count = 0
      }
      this.clear()
      this.draw(count)
    }, 200)
  }
  closeAnima() {
    clearInterval(Number(this.timer))
    this.timer = null
  }
}
